package com.cjj;

import com.cjj.library.ResourceTable;
import com.ryan.ohos.extension.event.DispatchHelper;
import com.ryan.ohos.extension.event.impl.ViewGroupHelper;
import com.ryan.ohos.extension.event.interfaces.ViewGroup;
import com.ryan.ohos.extension.nested.component.NestedListContainer;
import ohos.agp.animation.AnimatorProperty;
import ohos.agp.animation.AnimatorValue;
import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.components.ComponentContainer;
import ohos.agp.components.StackLayout;
import ohos.agp.utils.Color;
import ohos.agp.utils.LayoutAlignment;
import ohos.app.Context;
import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;
import ohos.hiviewdfx.HiLog;
import ohos.multimodalinput.event.TouchEvent;

import java.math.BigDecimal;

public class MaterialRefreshLayout extends StackLayout implements Component.TouchEventListener, ViewGroup {
    public static final String Tag = MaterialRefreshLayout.class.getSimpleName();
    private final static int DEFAULT_WAVE_HEIGHT = 140;
    private final static int HIGHER_WAVE_HEIGHT = 180;
    private final static int DEFAULT_HEAD_HEIGHT = 70;
    private final static int hIGHER_HEAD_HEIGHT = 100;
    private final static int DEFAULT_PROGRESS_SIZE = 50;
    private final static int BIG_PROGRESS_SIZE = 60;
    private final static int PROGRESS_STOKE_WIDTH = 3;

    private MaterialHeaderView mMaterialHeaderView;
    private MaterialFooterView mMaterialFooterView;
    private SunLayout mSunLayout;
    private boolean isOverlay;
    private int waveType;
    private int waveColor;
    protected float mWaveHeight;
    protected float mHeadHeight;
    private Component mChildView;
    protected boolean isRefreshing;
    private float mTouchY;
    private float mCurrentY;
    private float headHeight;
    private float waveHeight;
    private int[] colorSchemeColors;
    private int progressTextColor;
    private int progressValue, progressMax;
    private boolean showArrow = true;
    private int textType;
    private MaterialRefreshListener refreshListener;
    private boolean showProgressBg;
    private int progressBg;
    private boolean isShowWave;
    private int progressSizeType;
    private int progressSize = 0;
    private boolean isLoadMoreing;
    private boolean isLoadMore;
    private boolean isSunStyle = false;
    private ViewGroupHelper impl;

    public MaterialRefreshLayout(Context context) {
        this(context, null);
    }

    public MaterialRefreshLayout(Context context, AttrSet attrs) {
        this(context, attrs, null);
    }

    public MaterialRefreshLayout(Context context, AttrSet attrs, String defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context, attrs, defStyleAttr);
    }

    private void init(Context context, AttrSet attrs, String defstyleAttr) {
        setTouchEventListener(this::onTouchEvent);
        impl = new ViewGroupHelper(this);
        setBindStateChangedListener(new BindStateChangedListener() {
            @Override
            public void onComponentBoundToWindow(Component component) {
                onAttachedToWindow(attrs);
            }

            @Override
            public void onComponentUnboundFromWindow(Component component) {

            }
        });
        if (getChildCount() > 1) {
            throw new RuntimeException("can only have one child widget");
        }
        if (attrs != null) {
            isOverlay = AttrUtils.getBoolean(attrs, "overlay", false);
            /**attrs for materialWaveView*/
            String wavetype = AttrUtils.getString(attrs, "wave_height_type");
            if ("normal".equals(wavetype)) {
                waveType = 0;
            } else if ("higher".equals(wavetype)) {
                waveType = 1;
            } else {
                waveType = 0;
            }
            waveColor = AttrUtils.getColor(attrs, "wave_color", Color.WHITE.getValue());
            isShowWave = AttrUtils.getBoolean(attrs, "wave_show", true);
            /**attrs for circleprogressbar*/
            colorSchemeColors = new int[]{ResourceTable.Color_material_red, ResourceTable.Color_material_green,
                    ResourceTable.Color_material_blue, ResourceTable.Color_material_yellow};
            showArrow = AttrUtils.getBoolean(attrs, "progress_show_arrow", true);
            textType = AttrUtils.getInteger(attrs, "progress_text_visibility", 1);
            progressTextColor = AttrUtils.getColor(attrs, "progress_text_color", Color.BLACK.getValue());
            progressValue = AttrUtils.getInteger(attrs, "progress_value", 0);
            progressMax = AttrUtils.getInteger(attrs, "progress_max_value", 100);
            showProgressBg = AttrUtils.getBoolean(attrs, "progress_show_circle_backgroud", true);
            progressBg = AttrUtils.getColor(attrs, "progress_backgroud_color", CircleProgressBar.DEFAULT_CIRCLE_BG_LIGHT);
            progressSizeType = AttrUtils.getInteger(attrs, "progress_size_type", 0);
            if (progressSizeType == 0) {
                progressSize = DEFAULT_PROGRESS_SIZE;
            } else {
                progressSize = BIG_PROGRESS_SIZE;
            }
            isLoadMore = AttrUtils.getBoolean(attrs, "isLoadMore", false);
        }
        if (waveType == 0) {
            headHeight = DEFAULT_HEAD_HEIGHT;
            waveHeight = DEFAULT_WAVE_HEIGHT;
            Contants.getInstance().setDefaulHeadHeight(DEFAULT_HEAD_HEIGHT);
            Contants.getInstance().setDefaulWaveHeight(DEFAULT_WAVE_HEIGHT);
        } else {
            headHeight = hIGHER_HEAD_HEIGHT;
            waveHeight = HIGHER_WAVE_HEIGHT;
            Contants.getInstance().setDefaulHeadHeight(hIGHER_HEAD_HEIGHT);
            Contants.getInstance().setDefaulWaveHeight(HIGHER_WAVE_HEIGHT);
        }
    }

    protected void onAttachedToWindow(AttrSet attrs) {
        HiLog.info(Contants.LABEL, "onAttachedToWindow");
        Context context = getContext();
        mChildView = getComponentAt(0);

        if (mChildView == null) {
            return;
        }

        setWaveHeight(Util.dip2px(context, waveHeight));
        setHeaderHeight(Util.dip2px(context, headHeight));

        if (isSunStyle) {
            mSunLayout = new SunLayout(context);
            LayoutConfig layoutParams = new LayoutConfig(ComponentContainer.LayoutConfig.MATCH_PARENT, Util.dip2px(context, hIGHER_HEAD_HEIGHT));
            layoutParams.alignment = LayoutAlignment.TOP;
            mSunLayout.setLayoutConfig(layoutParams);
            mSunLayout.setVisibility(HIDE);
            setHeaderView(mSunLayout);
        } else {
            mMaterialHeaderView = new MaterialHeaderView(context);
            LayoutConfig layoutParams = new LayoutConfig(ComponentContainer.LayoutConfig.MATCH_PARENT, Util.dip2px(context, 140));
            layoutParams.alignment = LayoutAlignment.TOP;
            mMaterialHeaderView.setLayoutConfig(layoutParams);
            mMaterialHeaderView.setWaveColor(isShowWave ? waveColor : Color.TRANSPARENT.getValue());
            mMaterialHeaderView.showProgressArrow(showArrow);
            mMaterialHeaderView.setProgressSize(progressSize);
            mMaterialHeaderView.setProgressColors(colorSchemeColors);
            mMaterialHeaderView.setProgressStokeWidth(PROGRESS_STOKE_WIDTH);
            mMaterialHeaderView.setTextType(textType);
            mMaterialHeaderView.setProgressTextColor(progressTextColor);
            mMaterialHeaderView.setProgressValue(progressValue);
            mMaterialHeaderView.setProgressValueMax(progressMax);
            mMaterialHeaderView.setIsProgressBg(showProgressBg);
            mMaterialHeaderView.setProgressBg(progressBg);
            mMaterialHeaderView.setVisibility(HIDE);
            setHeaderView(mMaterialHeaderView);
        }
        mMaterialFooterView = new MaterialFooterView(context);
        LayoutConfig layoutParams2 = new LayoutConfig(ComponentContainer.LayoutConfig.MATCH_PARENT, Util.dip2px(context, hIGHER_HEAD_HEIGHT));
        layoutParams2.alignment = LayoutAlignment.BOTTOM;
        mMaterialFooterView.setLayoutConfig(layoutParams2);
        mMaterialFooterView.showProgressArrow(showArrow);
        mMaterialFooterView.setProgressSize(progressSize);
        mMaterialFooterView.setProgressColors(colorSchemeColors);
        mMaterialFooterView.setProgressStokeWidth(PROGRESS_STOKE_WIDTH);
        mMaterialFooterView.setTextType(textType);
        mMaterialFooterView.setProgressValue(progressValue);
        mMaterialFooterView.setProgressValueMax(progressMax);
        mMaterialFooterView.setIsProgressBg(showProgressBg);
        mMaterialFooterView.setProgressBg(progressBg);
        mMaterialFooterView.setVisibility(HIDE);
        setFooderView(mMaterialFooterView);
    }

    private void soveLoadMoreLogic() {
        isLoadMoreing = true;
        mMaterialFooterView.setVisibility(VISIBLE);
        mMaterialFooterView.onBegin(this);
        mMaterialFooterView.onRefreshing(this);
        System.out.println(mMaterialFooterView.getHeight() + "-------soveLoadMoreLogic");
        if (refreshListener != null) {
            refreshListener.onRefreshLoadMore(MaterialRefreshLayout.this);
        }
    }

    @Override
    public boolean onTouchEvent(Component component, TouchEvent e) {
        return DispatchHelper.dispatch(component, e);
    }

    public void setSunStyle(boolean isSunStyle) {
        this.isSunStyle = isSunStyle;
    }

    public void autoRefresh() {
        EventHandler eventHandler = new EventHandler(EventRunner.getMainEventRunner());
        eventHandler.postTask(new Runnable() {
            @Override
            public void run() {
                if (!isRefreshing) {
                    if (mMaterialHeaderView != null) {
                        mMaterialHeaderView.setVisibility(VISIBLE);

                        if (isOverlay) {
//                            mMaterialHeaderView.getLayoutConfig().height = (int) mHeadHeight;
                            mMaterialHeaderView.setHeight((int) mHeadHeight);
                            mMaterialHeaderView.postLayout();
                        } else {
                            createAnimatorTranslationY(mChildView, mHeadHeight, mMaterialHeaderView);
                        }
                    } else if (mSunLayout != null) {
                        mSunLayout.setVisibility(VISIBLE);
                        if (isOverlay) {
//                            mSunLayout.getLayoutConfig().height = (int) mHeadHeight;
                            mSunLayout.setHeight((int) mHeadHeight);
                            mSunLayout.postLayout();
                        } else {
                            createAnimatorTranslationY(mChildView, mHeadHeight, mSunLayout);
                        }
                    }
                    updateListener();
                }
            }
        }, 50);
    }

    public void autoRefreshLoadMore() {
        EventHandler.current().postTask(new Runnable() {
            @Override
            public void run() {
                if (isLoadMore) {
                    soveLoadMoreLogic();
                } else {
                    throw new RuntimeException("you must setLoadMore ture");
                }
            }
        });
    }

    public void updateListener() {
        isRefreshing = true;
        if (mMaterialHeaderView != null) {
            mMaterialHeaderView.onRefreshing(MaterialRefreshLayout.this);
        } else if (mSunLayout != null) {
            mSunLayout.onRefreshing(MaterialRefreshLayout.this);
        }
        if (refreshListener != null) {
            refreshListener.onRefresh(MaterialRefreshLayout.this);
        }

    }

    public void setLoadMore(boolean isLoadMore) {
        this.isLoadMore = isLoadMore;
    }

    public void setProgressColors(int[] colors) {
        this.colorSchemeColors = colors.clone();
    }

    public void setShowArrow(boolean showArrow) {
        this.showArrow = showArrow;
    }

    public void setShowProgressBg(boolean showProgressBg) {
        this.showProgressBg = showProgressBg;
    }

    public void setWaveColor(int waveColor) {
        this.waveColor = waveColor;
    }

    public void setWaveShow(boolean isShowWave) {
        this.isShowWave = isShowWave;
    }

    public void setIsOverLay(boolean isOverLay) {
        this.isOverlay = isOverLay;
    }

//    public void setProgressValue(int progressValue) {
//        this.progressValue = progressValue;
//        mMaterialHeaderView.setProgressValue(progressValue);
//    }

    public void createAnimatorTranslationY(final Component mChildView, final float h, final StackLayout sunLayout) {
        float currentY = mChildView.getTranslationY();
//        mChildView.setTranslationY(h);
        AnimatorValue animatorValue = new AnimatorValue();
        animatorValue.setDuration(250);
        animatorValue.setValueUpdateListener(new AnimatorValue.ValueUpdateListener() {
            @Override
            public void onUpdate(AnimatorValue animatorValue, float value) {
                float y = new BigDecimal(value).multiply((new BigDecimal(h).subtract(new BigDecimal(currentY)))).add(new BigDecimal(currentY)).floatValue();
                mChildView.setTranslationY(y);
                sunLayout.setHeight((int) y);
                sunLayout.invalidate();
            }
        });
        animatorValue.start();
    }

    /**
     * child view of this layout to scroll up
     *
     * @return Whether it is possible for the child view of this layout to
     * scroll up. Override this if the child view is a custom view.
     */
    public boolean canChildScrollUp() {
        if (mChildView == null) {
            return false;
        }
        return mChildView.getScrollValue(AXIS_Y) > 0;
    }

    public boolean canChildScrollDown() {
        if (mChildView instanceof NestedListContainer) {
            NestedListContainer container = (NestedListContainer) mChildView;
            if (container.getChildCount() < 1) {
                return false;
            }
            int itemHeight = container.getComponentAt(container.getFirstVisibleItemPosition()).getHeight();
            int scrollRange = itemHeight * container.getItemProvider().getCount() - container.getHeight() -
                    container.getPaddingBottom() - container.getPaddingTop();
            return container.getScrollY() < scrollRange;
        }
        return false;
    }

    public void setWaveHigher() {
        headHeight = hIGHER_HEAD_HEIGHT;
        waveHeight = HIGHER_WAVE_HEIGHT;
        Contants.getInstance().setDefaulHeadHeight(hIGHER_HEAD_HEIGHT);
        Contants.getInstance().setDefaulWaveHeight(HIGHER_WAVE_HEIGHT);
    }

    public void finishRefreshing() {
        if (mChildView != null) {
            AnimatorProperty viewPropertyAnimatorCompat = mChildView.createAnimatorProperty();
            viewPropertyAnimatorCompat.setDuration(200);
            viewPropertyAnimatorCompat.moveToY(0);
            viewPropertyAnimatorCompat.start();

            if (mMaterialHeaderView != null) {
                mMaterialHeaderView.onComlete(MaterialRefreshLayout.this);
            } else if (mSunLayout != null) {
                mSunLayout.onComlete(MaterialRefreshLayout.this);
            }

            if (refreshListener != null) {
                refreshListener.onfinish();
            }
        }
        isRefreshing = false;
        progressValue = 0;
    }

    public void finishRefresh() {

        EventHandler eventHandler = new EventHandler(EventRunner.getMainEventRunner());
        eventHandler.postTask(new Runnable() {
            @Override
            public void run() {
                finishRefreshing();
            }
        });
    }

    public void finishRefreshLoadMore() {
        EventHandler eventHandler = new EventHandler(EventRunner.getMainEventRunner());
        eventHandler.postTask(new Runnable() {
            @Override
            public void run() {
                if (mMaterialFooterView != null && isLoadMoreing) {
                    isLoadMoreing = false;
                    mMaterialFooterView.onComlete(MaterialRefreshLayout.this);
                }
            }
        });

    }

    private void setHeaderView(final Component headerView) {
        addComponent(headerView);
    }


    public void setHeader(final Component headerView) {
        setHeaderView(headerView);
    }

    public void setFooderView(final Component fooderView) {
        this.addComponent(fooderView);
    }


    public void setWaveHeight(float waveHeight) {
        this.mWaveHeight = waveHeight;
    }

    public void setHeaderHeight(float headHeight) {
        this.mHeadHeight = headHeight;
    }

    public void setMaterialRefreshListener(MaterialRefreshListener refreshListener) {
        this.refreshListener = refreshListener;
    }

    @Override
    public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
        impl.requestDisallowInterceptTouchEvent(disallowIntercept);
    }

    @Override
    public boolean onInterceptTouchEvent(TouchEvent ev) {
        if (isRefreshing) return true;
        switch (ev.getAction()) {
            case TouchEvent.PRIMARY_POINT_DOWN:
                mTouchY = ev.getPointerPosition(0).getY();
                mCurrentY = mTouchY;
                break;
            case TouchEvent.POINT_MOVE:
                float currentY = ev.getPointerPosition(0).getY();
                HiLog.info(Contants.LABEL, "POINT_MOVE----------");
                float dy = new BigDecimal(currentY).subtract(new BigDecimal(mTouchY)).floatValue();
                if (dy > 0 && !canChildScrollUp()) {
                    if (mMaterialHeaderView != null) {
                        mMaterialHeaderView.setVisibility(Component.VISIBLE);
                        mMaterialHeaderView.onBegin(this);
                    } else if (mSunLayout != null) {
                        mSunLayout.setVisibility(Component.VISIBLE);
                        mSunLayout.onBegin(this);
                    }
                    return true;
                } else if (dy < 0 && !canChildScrollDown() && isLoadMore) {
                    if (mMaterialFooterView != null && !isLoadMoreing) {
                        soveLoadMoreLogic();
                    }
                    return false;
                }
                break;
        }
        return false;
    }

    @Override
    public boolean dispatchTouchEvent(TouchEvent touchEvent) {
        return impl.dispatchTouchEvent(touchEvent);
    }

    @Override
    public boolean onTouchEvent(TouchEvent e) {
        if (isRefreshing) {
            return false;
        }
        switch (e.getAction()) {
            case TouchEvent.POINT_MOVE:
                mCurrentY = e.getPointerPosition(0).getY();
                float dy = new BigDecimal(mCurrentY).subtract(new BigDecimal(mTouchY)).floatValue();
                dy = Math.min(mWaveHeight * 2, dy);
                dy = Math.max(0, dy);
                if (mChildView != null) {
                    float offsetY = dy / 2;
                    float fraction = offsetY / mHeadHeight;
                    if (mMaterialHeaderView != null) {
                        mMaterialHeaderView.setHeight((int) offsetY);
                        mMaterialHeaderView.postLayout();
                        mMaterialHeaderView.onPull(this, fraction);
                    } else if (mSunLayout != null) {
                        mSunLayout.setHeight((int) offsetY);
                        mSunLayout.postLayout();
                        mSunLayout.startSunLineAnim(this);
                        mSunLayout.onPull(this, fraction);
                    }
                    if (!isOverlay)
                        mChildView.setTranslationY(offsetY);
                }
                return true;
            case TouchEvent.CANCEL:
                System.out.println("------------CANCEL");
            case TouchEvent.PRIMARY_POINT_UP:
                if (mChildView != null) {
                    if (mMaterialHeaderView != null) {
                        if (isOverlay) {
                            if (mMaterialHeaderView.getLayoutConfig().height > mHeadHeight) {
                                updateListener();
                                mMaterialHeaderView.setHeight((int) mHeadHeight);
                                mMaterialHeaderView.postLayout();

                            } else {
                                mMaterialHeaderView.setHeight(0);
                                mMaterialHeaderView.postLayout();
                            }

                        } else {
                            if (mChildView.getTranslationY() >= mHeadHeight) {
                                createAnimatorTranslationY(mChildView, mHeadHeight, mMaterialHeaderView);
                                updateListener();
                            } else {
                                createAnimatorTranslationY(mChildView, 0, mMaterialHeaderView);
                            }
                        }
                    } else if (mSunLayout != null) {
                        if (isOverlay) {
                            if (mSunLayout.getLayoutConfig().height > mHeadHeight) {
                                updateListener();
                                mSunLayout.setHeight((int) mHeadHeight);
                                mSunLayout.invalidate();
                            } else {
                                mSunLayout.setHeight(0);
                                mSunLayout.invalidate();
                            }

                        } else {
                            if (mChildView.getTranslationY() >= mHeadHeight) {
                                createAnimatorTranslationY(mChildView, mHeadHeight, mSunLayout);
                                updateListener();
                            } else {
                                createAnimatorTranslationY(mChildView, 0, mSunLayout);
                            }
                        }
                    }
                }
                return true;
        }

        return false;
    }

    @Override
    public boolean isConsumed() {
        return impl.isConsumed();
    }
}
